﻿using Abp;
using Abp.Collections.Extensions;
using Abp.Dependency;
using Mt.Site.Core.WorkFlows.Design;
using Mt.Site.Core.WorkFlows.Diy.Plugin;
using Mt.Site.Core.WorkFlows.Process;
using Mt.Site.Core.WorkFlows.Process.Models;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace Mt.Site.Core.WorkFlows.Diy
{
    public class WorkFlowPluginManager : IWorkFlowPluginManager, ITransientDependency
    {
        private readonly IWorkFlowPluginConfiguration _workFlowPluginConfiguration;

        public WorkFlowPluginManager(IWorkFlowPluginConfiguration workFlowPluginConfiguration)
        {
            _workFlowPluginConfiguration = workFlowPluginConfiguration;
        }

        public IDisposableDependencyObjectWrapper<WorkFlowPluginFunctionsBase> GetWorkFlowDiyFunction(
            IWorkflowDefinition workflowDefinition, IIocResolver iocResolver)
        {
            string functionName = workflowDefinition.Definition.OptionFunction;
            if (!string.IsNullOrEmpty(functionName))
            {
                foreach (var item in _workFlowPluginConfiguration.WorkFlowPluginProviders)
                {
                    if (item.Key == functionName)
                    {
                        return iocResolver.ResolveAsDisposable<WorkFlowPluginFunctionsBase>(item.Value);
                    }
                }
            }

            return NullWorkFlowDiyFunctionsWrapper.Instance;
        }

        public IDisposableDependencyObjectWrapper<WorkFlowNodePluginFunctionsBase> GetWorkFlowNodeDiyFunction(
            IWorkflowNodeDefinition workflowNodeDefinition, IIocResolver iocResolver)
        {
            string functionName = workflowNodeDefinition.Definition.OptionFunction;
            if (!string.IsNullOrEmpty(functionName))
            {
                foreach (var item in _workFlowPluginConfiguration.WorkFlowNodePluginProviders)
                {
                    if (item.Key == functionName)
                    {
                        return iocResolver.ResolveAsDisposable<WorkFlowNodePluginFunctionsBase>(item.Value);
                    }
                }
            }
            return NullWorkFlowNodeDiyFunctionsWrapper.Instance;
        }

        public IDisposableDependencyObjectWrapper<IAction> GetAction(string actionName, IIocResolver iocResolver)
        {
            var actionType = GetActionType(actionName);
            return iocResolver.ResolveAsDisposable<IAction>(actionType);
        }

        public async Task<List<WorkFlowActionDto>> GetActionListAsync(IWorkFlowManager workFlowManager)
        {
            var list = new List<WorkFlowActionDto>();
            using (var scope = workFlowManager.IocResolver.CreateScope())
            {
                foreach (var actionType in _workFlowPluginConfiguration.ActionProviders)
                {
                    var action = scope.Resolve<IAction>(actionType.Value);
                    if (await action.IsShowAsync(workFlowManager))
                    {
                        list.Add(new WorkFlowActionDto
                        {
                            Name = action.UniqueName,
                            DisplayName = await action.DisplayName(workFlowManager),
                            NeedSelectUsers = action.NeedUserListArg,
                            NeedReply = action.NeedReply(workFlowManager),
                            JsActionName = action.JsActionName,
                            JsOnSuccessActionName = action.JsOnSuccessActionName,
                            NeedCheckState = action.NeedCheckState
                        });
                    }
                }
            }
            return list;
        }

        private Type GetActionType(string actionName)
        {
            if(string.IsNullOrEmpty(actionName))
            {
                throw new AbpException($"Could not find a action with given name: {actionName}");
            }

            var actionType = _workFlowPluginConfiguration.ActionProviders.GetOrDefault(actionName);
            if (actionType == null)
            {
                throw new AbpException($"Could not find a action with given name: {actionName}");
            }

            return actionType;
        }
    }
}
